﻿
Imports System.DateTime
Imports System.Threading
Imports osi.root.formation
Imports osi.root.connector
Imports osi.root.utils
Imports osi.root.lock
Imports osi.root.envs
Imports osi.root.constants

Friend Module host_run
    Private ReadOnly expected_end_ms As Int64
    Private using_threads As Int32 = 0
    Private running_cases As Int32 = 0

    Sub New()
        expected_end_ms = Now().milliseconds() + minute_to_milliseconds(24 * 60)
    End Sub

    Private Sub run(ByVal c As case_info, ByVal started As pointer(Of Boolean))
        assert(Not c Is Nothing)
        Interlocked.Increment(running_cases)

        If Not self_health_stage() Then
            Dim msg() As Object = Nothing
            msg = {"start running ", c.full_name(), " at ", short_time()}
            If utt_report_case_name Then
                utt_raise_error(msg)
            Else
                raise_error(msg)
            End If
        End If

        Dim startms As Int64 = 0
        startms = Now().milliseconds()
        Interlocked.Add(using_threads, c.case.preserved_processors())
        eva(started, True)
        If assert_true(do_(AddressOf c.case.prepare, False), "failed to prepare case ", c.full_name()) Then
            assert_true(do_(AddressOf c.case.run, False), "failed to run case ", c.full_name())
            assert_true(do_(AddressOf c.case.finish, False), "failed to finish case ", c.full_name())
        End If
        Interlocked.Add(using_threads, -c.case.preserved_processors())

        If Not self_health_stage() Then
            Dim msg() As Object = Nothing
            msg = {"finish running ",
                   c.full_name(),
                   ", total time in milliseconds ",
                   Now().milliseconds() - startms}
            If utt_report_case_name Then
                utt_raise_error(msg)
            Else
                raise_error(msg)
            End If
        End If

        'for mono in fact
        waitfor_gc_collect()

        Interlocked.Decrement(running_cases)
    End Sub

    Private Function go_through() As Boolean
        assert(commandline.has_specific_selections() OrElse
               assert_less_or_equal(Now().milliseconds(), expected_end_ms))
        Dim rtn As Boolean = False
        For i As Int32 = 0 To cases.size() - 1
            If Not cases(i).finished Then
                rtn = True
                If (cases(i).case.preserved_processors() >= 0 AndAlso
                    cases(i).case.preserved_processors() + using_threads <= Environment.ProcessorCount()) OrElse
                   using_threads = 0 Then
                    cases(i).finished = True
                    Dim j As Int32 = 0
                    j = i
                    Dim started As pointer(Of Boolean) = Nothing
                    started = New pointer(Of Boolean)(False)
                    queue_in_managed_threadpool(Sub() run(cases(j), started))
                    timeslice_sleep_wait_when(Function() Not (+started))
                End If
            End If
        Next

        Return rtn
    End Function

    Public Sub run()
        Dim wait_ms As Int64 = 0
        If self_health_stage() Then
            wait_ms = half_timeslice_length_ms
        Else
            wait_ms = seconds_to_milliseconds(10)
        End If
        sleep_wait_when(Function() go_through(), wait_ms)
        sleep_wait_when(Function() running_cases > 0, wait_ms)
    End Sub
End Module
